/*
 * Created on Sat Jun 30 2018 by Ronnie Ren (zhaosong.ren) from Accenture
 *
 * Copyright (c) 2018 DingXin information & technology limited company.
 */

import { Injectable } from "@angular/core";
import { HttpService, HTTPMethods } from "http-service";
import { CurdService } from "../../models/services/curd.service";
import { SyncUtilService } from "./sync.util.service";
import { StorageService } from "../../models/services/storage.service";
import { Observable } from "rxjs";
import { BillDto } from "../../models/dto/bill.dto";
import { SyncStatus } from "../../models/sync-status";
import { Bill } from "../../models/transform/bill";
import { BillService } from "../../models/services/bill.service";
import { AttachmentService } from "../../models/services/attachment.service";
import { Attachment } from "../../models/transform/attachment";
import { API } from "../../models/api-path-extension";
import { ResponseData } from "../../models/response-data";
import { ResponseAttachment } from "../../models/response/response-attachments";
import { AttachmentDto } from "../../models/dto/attachment.dto";
import { WorkOrderService } from "../../models/services/work-order.service";
import {WorkOrderType, WorkOrder, WorkOrderStatus} from "../../models/transform/work-order";
import {WorkOrderDto} from "../../models/dto/work-orders.dto";
import { SecureStorageService } from "../secure-storage.services";
import {InspectionRecords} from "../../models/transform/inspection/inspection-records";
import { InspectionRecordsDto } from "../../models/dto/inspection/inspection-records.dto";
import {InspectionRecordsService} from "../../models/services/inspection/inspection-records.service";
import {InspectionOperationsTicketsService} from "../../models/services/inspection/inspection-operation-tickets.service";
import { InspectionOperationsTickets } from "../../models/transform/inspection/inspection-operation-tickets";
import { InspectionOperationsTicketsDto } from "../../models/dto/inspection/inspection-operation-tickets.dto";
import {InspectionTasks} from "../../models/transform/inspection/inspection-tasks";
import {InspectionTasksDto} from "../../models/dto/inspection/inspection-tasks.dto";
import {RoleStatus} from "../../models/role.status";
import { UtilsService } from "../utils.services";
import { Device } from "@ionic-native/device";
import {InspectionSyncService} from "./inspection-sync.servie";
// import { SyncService } from "./sync.servie";
import { UserCharacteristicRelationshipService } from "../../models/services/user-characteristic-relationship.service";
import { UserCharacteristicRelationship } from "../../models/transform/user-characteristic-relationship";
import { UserCharacteristicRelationshipDto } from "../../models/dto/user-characteristic-relationship.dto";
import {LastFetchingDate} from "../../models/lastFetchingDate";
import {StorageDto} from "../../models/dto/storage.dto";
import {CustomStorage} from "../../models/transform/custom-storage";

export enum NetStatus {
  work = "ethernet, wifi, 2g, 3g, 4g, cellular",
  noWork = "unknown, none"
}

declare var window: {
  localStorage: {
    getItem: any
  }
};

@Injectable()
export class SyncPushService {

  private isPushing = false;
  private syncStatus: SyncStatus;
  private inspectionSync: SyncStatus;
  private otherSync: SyncStatus;

  constructor(
    private httpService: HttpService,
    private curdService: CurdService,
    private device: Device,
    private syncUtilService: SyncUtilService,
    private billService: BillService,
    private workOrderService: WorkOrderService,
    private customeStorageService: StorageService,
    private attachmentService: AttachmentService,
    public utilsService: UtilsService,
    private inspectionRecordsService: InspectionRecordsService,
    private inspectionOperationsTicketsService: InspectionOperationsTicketsService,
    private storage: SecureStorageService,
    private inspectionSyncService: InspectionSyncService,
    // public syncService: SyncService,
    public userCharacteristicRelationshipService: UserCharacteristicRelationshipService

  ) {

  }

  startPush(syncStatus: SyncStatus = SyncStatus.None) {
    // let role = window.localStorage.getItem("role");
    // let marketing = new RegExp(RoleStatus.marketing);
    // let producer = new RegExp(RoleStatus.producer);
    return Observable.combineLatest(
      this.chargeAndResumptionStartPush(),
      this.inspectionStartPush(),
      this.userFeaturePush()
    )
      .do(() => {
        this.syncUtilService.saveApiLastFetchingDate({ key: LastFetchingDate.pushTime, value: new Date().getTime().toString() });
      });
      // .flatMap(() => {
      //   if (marketing.test(role)) {
      //     return this.syncService.startFetch()
      //       .do(() => {
      //         this.utilsService.hiddenLoading();
      //       });
      //   } else {
      //     return Observable.of(false);
      //   }
      // })
      // .flatMap(() => {
      //   if (producer.test(role)) {
      //     return this.inspectionSyncService.startFetch()
      //       .do(() => {
      //         this.utilsService.hiddenLoading();
      //       });
      //   } else {
      //     return Observable.of(false);
      //   }
      // });
  }

  // charge && resumption
  chargeAndResumptionStartPush(syncStatus: SyncStatus = SyncStatus.None) {
    let role = window.localStorage.getItem("role");
    let marketing = new RegExp(RoleStatus.marketing);
    this.syncStatus = syncStatus;
    if (marketing.test(role)) {
      this.utilsService.showLoading();
      return this.pushLevel2Notices()
        .flatMap(() => {
        // TODO powerCut && recover
          return this.pushPowerCutApply().flatMap(() => {
            // TODO
            this.utilsService.hiddenLoading();
            if (this.syncStatus === SyncStatus.None) {
              return this.chargeAndResumptionStartPush(SyncStatus.Failure);
            } else {
              return Observable.of(false);
            }
          });
      });
    } else {
      this.utilsService.hiddenLoading();
      return Observable.of(false);
    }
  }

  inspectionStartPush(syncStatus: SyncStatus = SyncStatus.None) {
    let role = window.localStorage.getItem("role");
    let producer = new RegExp(RoleStatus.producer);
    this.inspectionSync = syncStatus;
    if (producer.test(role)) {
      this.utilsService.showLoading();
      return this.pushInspectionRecord()
        .flatMap(() => {
        // TODO operationTickets
          return this.pushInspectionOperationTickets()
            .flatMap(() => {
              // TODO
              this.utilsService.hiddenLoading();
              if (this.inspectionSync === SyncStatus.None) {
                return this.inspectionStartPush(SyncStatus.Failure);
              } else {
                // add refresh
                return Observable.of(false);
              }
            });
      });
    } else {
      this.utilsService.hiddenLoading();
      return Observable.of(false);
    }
  }

  userFeaturePush(syncStatus: SyncStatus = SyncStatus.None) {
    let role = window.localStorage.getItem("role");
    let marketing = new RegExp(RoleStatus.marketing);
    this.otherSync = syncStatus;
    if (marketing.test(role)) {
      this.utilsService.showLoading();
      return Observable.combineLatest(
        this.getUserFeatureAndPush()
      )
        .do(() => {
          this.getSyncStatus(this.otherSync);
        })
        .flatMap(() => {
          this.utilsService.hiddenLoading();
          if (this.otherSync === SyncStatus.None) {
            return this.userFeaturePush(SyncStatus.Failure);
          } else {
            // add refresh
            return Observable.of(false);
          }
      });
    }
    else {
      this.utilsService.hiddenLoading();
      return Observable.of(false);
    }
  }

  getUserFeatureAndPush() {
    return this.userCharacteristicRelationshipService.fetchUsesBySyncStatus(this.otherSync)
      .map((userCharacteristicRelationships) => {
        return userCharacteristicRelationships.map((userCharacteristicRelationship) => {
          return {
            markNo: userCharacteristicRelationship.markNo,
            customerNo: userCharacteristicRelationship.customerNo,
            markUserAccount: userCharacteristicRelationship.markUserAccount
          };
        });
      })
      .flatMap((userCharacteristicRelationships) => {
        let api = new API().path({ path: "pushUserCharacteristicsRelation", method: HTTPMethods.Post });
        return this.httpService.fetchWithPath(api, userCharacteristicRelationships)
          .flatMap((res) => {
            if (res.code === 200) {
              return this.userCharacteristicRelationshipService.updateUserCharacteristicRelationUserSyncStatus(this.otherSync, SyncStatus.Success);
            } else {
              return this.userCharacteristicRelationshipService.updateUserCharacteristicRelationUserSyncStatus(this.otherSync, SyncStatus.Failure);
            }
          });
      });
  }

  pushInspectionOperationTickets(): Observable<any> {
    return this.inspectionOperationsTicketsService.fetchInspectionOperationTicketsBySyncStatus([this.inspectionSync], 1)
      .flatMap((inspectionOperationsTickets: Array<InspectionOperationsTickets>) => {
        if (inspectionOperationsTickets && inspectionOperationsTickets.length < 1) {
          return Observable.of(false);
        }
        // 获取到一条billMapping
        let inspectionOperationsTicket = inspectionOperationsTickets[0];
        let attachments = inspectionOperationsTicket.pictureAttachments.filter((attachment) => attachment.syncStatus === this.inspectionSync);
        if (attachments.length > 0) {
          return this.pushAttachmentAndUpdateInspectionOperationsTickets(attachments, inspectionOperationsTicket);
        }
        return this.postInspectionOperationTickets(inspectionOperationsTicket);
      })
      .flatMap((result) => {
        if (result) {
          return this.pushInspectionOperationTickets();
        }
        return Observable.of(false);
      });
  }

  pushInspectionRecord(): Observable<boolean> {
    return this.inspectionRecordsService.fetchInspectionRecordsBySyncStatus([this.inspectionSync], 1)
      .flatMap((inspectionRecords: Array<InspectionRecords>) => {
        if (inspectionRecords && inspectionRecords.length < 1) {
          return Observable.of(false);
        }
        // 获取到一条billMapping
        let inspectionRecord = inspectionRecords[0];
        let attachments = inspectionRecord.pictureAttachments.filter((attachment) => attachment.syncStatus === this.inspectionSync);
        if (attachments.length > 0) {
          return this.pushAttachmentAndUpdateInspectionRecords(attachments, inspectionRecord);
        }
        return this.postInspectionRecord(inspectionRecord);
      })
      .flatMap((result) => {
        if (result) {
          return this.pushInspectionRecord();
        }
        return Observable.of(false);
      });
  }

  pushPowerCutApply(): Observable<boolean> {
    return this.workOrderService.fetchWorkOrderBySyncStatus([this.syncStatus], 1)
      .flatMap((workOrders: Array<WorkOrder>) => {
        console.log(this.syncStatus);
        if (workOrders && workOrders.length < 1) {
          return Observable.of(false);
        }
        let workOrder = workOrders[0];
        let attachments = workOrder.noticeAttachments.filter((attachment) => attachment.syncStatus === this.syncStatus);
        // workOrder sync
        if (attachments.length > 0) {
          return this.pushAttachmentAndUpdateWorkOrder(attachments, workOrder);
        }
        if (workOrder.type === WorkOrderType.POWERCUT) {
          return this.postPowerCutApply(workOrder);
        } else {
          // recover
          if (workOrder.type === WorkOrderType.POWERRECOVERY && workOrder.id) {
            // recover powerCut
            return this.postRecoverApply(workOrder);
          }
        }
      });
  }

  pushLevel2Notices(): Observable<boolean> {
    return this.billService.fetchBillsBySyncStatus([this.syncStatus], 1)
      .flatMap((bills: Array<Bill>) => {
        if (bills && bills.length < 1) {
          return Observable.of(false);
        }
        // 获取到一条billMapping
        let bill = bills[0];
        let attachments = bill.noticeAttachments.filter((attachment) => attachment.syncStatus === this.syncStatus);
        if (attachments.length > 0) {
          // return this.cyclePushAttachmentAndUpdateBill(attachments, bill);
          return this.pushAttachmentAndUpdateBill(attachments, bill);
        }
        return this.postNotice(bill);
      })
      .flatMap((result) => {
        if (result) {
          return this.pushLevel2Notices();
        }
        return Observable.of(false);
      });
  }

  public getBase64(url) {
    return Observable.create( (subscriber) => {
      let Img = new Image();
      let dataURL = '';
      if (this.device.cordova) {
        Img.src = url;
      } else {
        Img.src = "../../../assets/imgs/charge.png";
      }
      Img.setAttribute("crossOrigin", 'Anonymous');
      Img.onload = () => {
        let canvas = document.createElement("canvas");
        let width = Img.width;
        let height = Img.height;
        canvas.width = width;
        canvas.height = height;
        canvas.getContext("2d").drawImage(Img, 0, 0, width, height);
        dataURL = canvas.toDataURL('image/jpeg');
        // callback(dataURL);
        subscriber.next([dataURL]);
        subscriber.complete();
      };
    });
  }

  private pushAttachmentAndUpdateBill(attachments: Array<Attachment> , bill: Bill, index: number = 0): Observable<boolean> {
    // let uploadAPI = new API().path({ path: "uploadAttachment", method: HTTPMethods.Post });
    // return this.httpService.uploadFile(uploadAPI, attachment.path, attachment.attachmentName)
      if (index >= attachments.length ) {
        // continue sync notice
        return this.postNotice(bill);
      }
      let attachment = attachments[index];
      return this.getBase64(attachment.path).flatMap((base64: Array<string>) => {
        let api = new API().path({ path: "uploadAttachment", method: HTTPMethods.Post });
        return this.httpService.fetchWithPath(api, {
          attachmentBase64: base64
        })
        // return this.httpService.post(uploadAPI, attachment.path, attachment.attachmentName)
          .flatMap((res: ResponseData) => {
            if (res.code === 200) {
              let data = res.data as ResponseAttachment;
              let oldAttachmentId = attachment.id;
              bill.updateAttachmentIdWithNewId(attachment.id, data[0].attachmentId);
              attachment.id = data[0].attachmentId; // 更新attachment id
              attachment.thumbnailId = data[0].thumbnailId; // 更新attachment thumbnailId
              attachment.syncStatus = SyncStatus.Success; // 更新attachment 同步状态
              let billDto = new BillDto();
              billDto.id = bill.id;
              billDto.attachmentIds = bill.noticeAttachments.map((att) => att.id).join(",");
              return this.curdService.beginTransaction()
                .updateObject(this.syncUtilService.toObjectDto(attachment, AttachmentDto), {id: oldAttachmentId}, ['id', 'thumbnailId', 'syncStatus'])
                .updateObject(billDto, {id: bill.id}, ['attachmentIds'])
                .commit()
                .flatMap(() => {
                  return this.pushAttachmentAndUpdateBill(attachments, bill, ++index);
                });
            } else {
              attachment.syncStatus = this.getSyncStatus(this.syncStatus);
              return this.curdService.beginTransaction()
                .updateObject(this.syncUtilService.toObjectDto(attachment, AttachmentDto), {id: attachment.id}, ['syncStatus'])
                .commit()
                .flatMap(() => {
                  return this.pushAttachmentAndUpdateBill(attachments, bill, ++index);
                });
            }
          });
      });
  }

  private pushAttachmentAndUpdateWorkOrder(attachments: Array<Attachment> , workOrder: WorkOrder, index: number = 0): Observable<boolean> {
    // let uploadAPI = new API().path({ path: "uploadAttachment", method: HTTPMethods.Post });
    // return this.httpService.uploadFile(uploadAPI, attachment.path, attachment.attachmentName)
    if (index >= attachments.length ) {
      // continue sync workOrder
      if (workOrder.type === WorkOrderType.POWERCUT) {
        // workOrder sync-----powerCut apply
        return this.postPowerCutApply(workOrder);
      } else {
        // recover
        if (workOrder.type === WorkOrderType.POWERRECOVERY && workOrder.id) {
          // recover powerCut
          return this.postRecoverApply(workOrder);
        }
      }
    }
    let attachment = attachments[index];
    return this.getBase64(attachment.path).flatMap((base64: Array<string>) => {
      let api = new API().path({ path: "uploadAttachment", method: HTTPMethods.Post });
      return this.httpService.fetchWithPath(api, {
        attachmentBase64: base64
      })
      // return this.httpService.post(uploadAPI, attachment.path, attachment.attachmentName)
        .flatMap((res: ResponseData) => {
          if (res.code === 200) {
            let data = res.data as ResponseAttachment;
            let oldAttachmentId = attachment.id;
            workOrder.updateAttachmentIdWithNewId(attachment.id, data[0].attachmentId);
            attachment.id = data[0].attachmentId; // 更新attachment id
            attachment.thumbnailId = data[0].thumbnailId; // 更新attachment thumbnailId
            attachment.syncStatus = SyncStatus.Success; // 更新attachment 同步状态
            let workOrderDto = new WorkOrderDto();
            workOrderDto.id = workOrder.id;
            workOrderDto.powerCutPhotoIds = workOrder.noticeAttachments.map((att) => att.id).join(",");
            return this.curdService.beginTransaction()
              .updateObject(this.syncUtilService.toObjectDto(attachment, AttachmentDto), {id: oldAttachmentId}, ['id', 'thumbnailId', 'syncStatus'])
              .updateObject(workOrderDto, {id: workOrder.id}, ['powerCutPhotoIds'])
              .commit()
              .flatMap(() => {
                return this.pushAttachmentAndUpdateWorkOrder(attachments, workOrder, ++index);
              });
          } else {
            attachment.syncStatus = this.getSyncStatus(this.syncStatus); // 更新attachment 同步状态
            return this.curdService.beginTransaction()
              .updateObject(this.syncUtilService.toObjectDto(attachment, AttachmentDto), {id: attachment.id}, ['syncStatus'])
              .commit()
              .flatMap(() => {
                return this.pushAttachmentAndUpdateWorkOrder(attachments, workOrder, ++index);
              });
          }
        });
    });
  }

  private pushAttachmentAndUpdateInspectionOperationsTickets(
    attachments: Array<Attachment>, inspectionOperationsTicket: InspectionOperationsTickets, index: number = 0): Observable<boolean> {
    if (index >= attachments.length ) {
      return this.postInspectionOperationTickets(inspectionOperationsTicket);
    }
    let attachment = attachments[index];
    return this.getBase64(attachment.path).flatMap((base64: Array<string>) => {
      let api = new API().path({ path: "uploadAttachment", method: HTTPMethods.Post });
      return this.httpService.fetchWithPath(api, {
        attachmentBase64: base64
      })
      // return this.httpService.post(uploadAPI, attachment.path, attachment.attachmentName)
        .flatMap((res: ResponseData) => {
          if (res.code === 200) {
            let data = res.data as ResponseAttachment;
            let oldAttachmentId = attachment.id;
            inspectionOperationsTicket.updateAttachmentIdWithNewId(attachment.id, data[0].attachmentId);
            attachment.id = data[0].attachmentId; // 更新attachment id
            attachment.thumbnailId = data[0].thumbnailId; // 更新attachment thumbnailId
            attachment.syncStatus = SyncStatus.Success; // 更新attachment 同步状态
            let inspectionOperationsDto = new InspectionOperationsTicketsDto();
            inspectionOperationsDto.taskId = inspectionOperationsTicket.taskId;
            inspectionOperationsDto.attachmentIds = inspectionOperationsTicket.pictureAttachments.map((att) => att.id).join(",");
            return this.curdService.beginTransaction()
              .updateObject(this.syncUtilService.toObjectDto(attachment, AttachmentDto), {id: oldAttachmentId}, ['id', 'thumbnailId', 'syncStatus'])
              .updateObject(inspectionOperationsDto, {id: inspectionOperationsTicket.id}, ['attachmentIds'])
              .commit()
              .flatMap(() => {
                return this.pushAttachmentAndUpdateInspectionOperationsTickets(attachments, inspectionOperationsTicket, ++index);
              });
          } else {
            // sync Error
            attachment.syncStatus = this.getSyncStatus(this.inspectionSync); // 更新attachment 同步状态
            return this.curdService.beginTransaction()
              .updateObject(this.syncUtilService.toObjectDto(attachment, AttachmentDto), {id: attachment.id}, ['syncStatus'])
              .commit()
              .flatMap(() => {
                return this.pushAttachmentAndUpdateInspectionOperationsTickets(attachments, inspectionOperationsTicket, ++index);
              });
          }
        });
    });
  }

  private pushAttachmentAndUpdateInspectionRecords(
    attachments: Array<Attachment> , inspectionRecord: InspectionRecords, index: number = 0): Observable<boolean> {
    if (index >= attachments.length ) {
      // continue sync notice
      return this.postInspectionRecord(inspectionRecord);
    }
    let attachment = attachments[index];
    return this.getBase64(attachment.path).flatMap((base64: Array<string>) => {
      let api = new API().path({ path: "uploadAttachment", method: HTTPMethods.Post });
      return this.httpService.fetchWithPath(api, {
        attachmentBase64: base64
      })
      // return this.httpService.post(uploadAPI, attachment.path, attachment.attachmentName)
        .flatMap((res: ResponseData) => {
          if (res.code === 200) {
            let data = res.data as ResponseAttachment;
            let oldAttachmentId = attachment.id;
            inspectionRecord.updateAttachmentIdWithNewId(attachment.id, data[0].attachmentId);
            attachment.id = data[0].attachmentId; // 更新attachment id
            attachment.thumbnailId = data[0].thumbnailId; // 更新attachment thumbnailId
            attachment.syncStatus = SyncStatus.Success; // 更新attachment 同步状态
            let inspectionRecordsDto = new InspectionRecordsDto();
            inspectionRecordsDto.taskId = inspectionRecord.taskId;
            inspectionRecordsDto.pictureAttachmentIds = inspectionRecord.pictureAttachments.map((att) => att.id).join(",");
            return this.curdService.beginTransaction()
              .updateObject(this.syncUtilService.toObjectDto(attachment, AttachmentDto), {id: oldAttachmentId}, ['id', 'thumbnailId', 'syncStatus'])
              .updateObject(inspectionRecordsDto, {taskId: inspectionRecord.taskId}, ['pictureAttachmentIds'])
              .commit()
              .flatMap(() => {
                return this.pushAttachmentAndUpdateInspectionRecords(attachments, inspectionRecord, ++index);
              });
          } else {
            // sync Error
            attachment.syncStatus = this.getSyncStatus(this.inspectionSync); // 更新attachment 同步状态
            return this.curdService.beginTransaction()
              .updateObject(this.syncUtilService.toObjectDto(attachment, AttachmentDto), {id: attachment.id}, ['syncStatus'])
              .commit()
              .flatMap(() => {
                return this.pushAttachmentAndUpdateInspectionRecords(attachments, inspectionRecord, ++index);
              });
          }

        });
    });
  }

  private getSyncStatus(syncStatus: SyncStatus) {
   return syncStatus === SyncStatus.None ? SyncStatus.Failure : SyncStatus.None;
  }

  private postNotice(bill: Bill): Observable<boolean> {
    let api = new API().path({ path: "postNotice", method: HTTPMethods.Post });
    let parameters = [{
      chargeDetailId: bill.chargeDetailId,
      noticeUploadTime: bill.noticeUploadTime,
      noticeImageId: bill.noticeAttachments.map((attachment) => attachment.id).join(","),
      noticeThrumnailId: bill.noticeAttachments.map((attachment) => attachment.thumbnailId).join(",")
    }];
    return this.httpService.fetchWithPath(api, parameters)
      .flatMap((res) => {
        let billDto = new BillDto();
        if (res.code === 200) {
          billDto.syncStatus = SyncStatus.Success;
        } else {
          billDto.syncStatus = this.getSyncStatus(this.syncStatus);
        }
        return this.curdService.beginTransaction()
          .updateObject(billDto, {id: bill.id}, ['syncStatus'])
          .commit();
      })
      .map(() => true);
  }

  // powerCut Apply
  private postPowerCutApply(workOrder: WorkOrder): Observable<boolean> {
    if (workOrder.applyId) {
      return this.postPowerCutRecord(workOrder, {
        id: workOrder.id,
        applyId: workOrder.applyId
      });
    } else {
      let api = new API().path({ path: "postPowerCutApply", method: HTTPMethods.Post });
      return Observable.combineLatest(
        this.storage.get("loginUserName"),
        this.storage.get("loginAccount")
      )
        .map((curLoginAccountArray) => {
          return {
            curLoginUserName: curLoginAccountArray[0],
            curLoginUserAccount: curLoginAccountArray[1]
          };
        })
        .flatMap((curLoginObj) => {
          let parameters = [{
            customerNo: workOrder.userId,
            chargeDetailId: workOrder.chargeDetailId,
            powerCutTime: workOrder.dueTime,
            powerCutType: 1,
            powerCutImmediate: workOrder.isPerform,
            powerCutReason: workOrder.reason,
            powerCutScope: workOrder.powerCutScope,
            powerCutApplyTime: workOrder.createdTime,
            powerCutApplyAccount: curLoginObj.curLoginUserName,
            powerCutApplyName: curLoginObj.curLoginUserAccount
          }];
          return this.httpService.fetchWithPath(api, parameters)
            .flatMap((resData) => {
              // 停电实施同步
              if (resData.code === 200 && resData.data.doneList.length > 0) {
                if (workOrder.workOrderStatus === WorkOrderStatus.EXECUTED) {
                  let workOrderDto = new WorkOrderDto();
                  workOrderDto.id = resData.data.doneList[0].orderNO;
                  workOrderDto.applyId = resData.data.doneList[0].recordID;
                  return this.curdService.beginTransaction()
                    .updateObject(workOrderDto, {id: workOrder.id}, ['id', 'applyId'])
                    .commit()
                    .flatMap(() => {
                      return this.postPowerCutRecord(workOrder, {
                        id: resData.data.doneList[0].orderNO,
                        applyId: resData.data.doneList[0].recordID
                      });
                    });
                } else {
                  // not need sync implement
                  let workOrderDto = new WorkOrderDto();
                  workOrderDto.id = resData.data.doneList[0].orderNO;
                  workOrderDto.applyId = resData.data.doneList[0].recordID;
                  workOrderDto.syncStatus = SyncStatus.Success;
                  return this.curdService.beginTransaction()
                    .updateObject(workOrderDto, {id: workOrder.id}, ['id', 'applyId', 'syncStatus'])
                    .commit();
                }
              } else {
                // sync error
                let workOrderDto = new WorkOrderDto();
                workOrderDto.syncStatus = this.getSyncStatus(this.syncStatus);
                return this.curdService.beginTransaction()
                  .updateObject(workOrderDto, {id: workOrder.id}, ['syncStatus'])
                  .commit();
              }
            })
            .map(() => true);
        });
    }
  }

  // powerCut record
  private postPowerCutRecord(workOrder: WorkOrder, applyResponse: {
    id: any,
    applyId: any
  }): Observable<boolean> {
    let api = new API().path({ path: "postPowerCutRecord", method: HTTPMethods.Post });
    return this.storage.get("loginUserName").flatMap((userName) => {
      let parameters = [{
        chargeDetailId: workOrder.chargeDetailId,
        applyId: applyResponse.applyId,
        orderNo: applyResponse.id,
        recordType: workOrder.type,
        performerOne: workOrder.performerOne,
        performerOneAccount: workOrder.performerOneAccount,
        performerTwo: workOrder.performerTwo,
        performerTwoAccount: workOrder.performerTwoAccount,
        sealType: workOrder.sealType,
        sealNo: workOrder.sealNO,
        sealDeviceId: workOrder.sealDeviceId,
        sealComponentId: workOrder.sealComponentId,
        meterReadingTotal: workOrder.meterReadingTotal,
        meterReadingTime: workOrder.meterReadingTime,
        performPhotoId: workOrder.noticeAttachments.map((att) => att.id).join(","),
        performThrumnailId: workOrder.noticeAttachments.map((att) => att.thumbnailId).join(","),
        recordDate: workOrder.recordDate,
        USER_ACCOUNT: userName
      }];
      return this.httpService.fetchWithPath(api, parameters)
        .flatMap((res) => {
          let workOrderDto = new WorkOrderDto();
          if (res.code === 200 && res.data.doneList.length > 0) {
            // workOrderDto.recordId = res.data.doneList[0].recordID;
            workOrderDto.syncStatus = SyncStatus.Success;
          } else {
            // sync error
            workOrderDto.syncStatus = this.getSyncStatus(this.syncStatus);
          }
          return this.curdService.beginTransaction()
            .updateObject(workOrderDto, {id: workOrder.id}, ['syncStatus'])
            .commit();
        })
        .map(() => true);
    });

  }

  // recover power apply
  private postRecoverApply(workOrder: WorkOrder): Observable<boolean> {
    if (workOrder.applyId) {
      return this.postPowerCutRecord(workOrder, {
        id: workOrder.id,
        applyId: workOrder.applyId
      });
    } else {
      let api = new API().path({ path: "postRecoverApply", method: HTTPMethods.Post });
      return Observable.combineLatest(
        this.storage.get("loginUserName"),
        this.storage.get("loginAccount")
      )
        .map((curLoginAccountArray) => {
          return {
            curLoginUserName: curLoginAccountArray[0],
            curLoginUserAccount: curLoginAccountArray[1]
          };
        })
        .flatMap((curLoginObj) => {
          let parameters = [{
            greenPass: 1,
            customerNo: workOrder.userId,
            chargeDetailId: workOrder.chargeDetailId,
            recoverTime: workOrder.dueTime,
            recoverApplyTime: workOrder.createdTime,
            recoverVerifyTime: workOrder.recoverVerifyTime,
            recoverApplyReason: workOrder.reason,
            recoverApplyAccount: curLoginObj.curLoginUserName,
            recoverApplyName: curLoginObj.curLoginUserAccount
          }];
          return this.httpService.fetchWithPath(api, parameters)
            .flatMap((resData) => {
              // TODO sync Error
              // 复电实施同步
              if (resData === 200 && resData.data.doneList.length > 0) {
                if (workOrder.workOrderStatus === WorkOrderStatus.EXECUTED) {
                  let workOrderDto = new WorkOrderDto();
                  workOrderDto.id = resData.data.doneList[0].orderNO;
                  workOrderDto.applyId = resData.data.doneList[0].recordID;
                  return this.curdService.beginTransaction()
                    .updateObject(workOrderDto, {id: workOrder.id}, ["id", "applyId"])
                    .commit()
                    .flatMap(() => {
                      return this.postPowerCutRecord(workOrder, {
                        id: resData.data.doneList[0].orderNO,
                        applyId: resData.data.doneList[0].recordID
                      });
                    });
                } else {
                  // not need sync implement
                  let workOrderDto = new WorkOrderDto();
                  workOrderDto.id = resData.data.doneList[0].orderNO;
                  workOrderDto.applyId = resData.data.doneList[0].recordID;
                  workOrderDto.syncStatus = SyncStatus.Success;
                  return this.curdService.beginTransaction()
                    .updateObject(workOrderDto, {id: workOrder.id}, ["id", "applyId", 'syncStatus'])
                    .commit();
                }
              } else {
                // error
                let workOrderDto = new WorkOrderDto();
                workOrderDto.syncStatus = this.getSyncStatus(this.syncStatus);
                return this.curdService.beginTransaction()
                  .updateObject(workOrderDto, {id: workOrder.id}, ['syncStatus'])
                  .commit();
              }
            })
            .map(() => true);
        });
    }
  }

  private postInspectionOperationTickets(inspectionOperationsTicket: InspectionOperationsTickets): Observable<boolean> {
    let api = new API().path({ path: "operationTicket", method: HTTPMethods.Post });
    let parameters = {
      id: inspectionOperationsTicket.id,
      planId: inspectionOperationsTicket.taskId,
      operateType: inspectionOperationsTicket.type,
      orderDept: inspectionOperationsTicket.fromCompany,
      orderMan: inspectionOperationsTicket.fromName,
      orderFromMan: inspectionOperationsTicket.toName,
      orderFromTime: inspectionOperationsTicket.orderTakenTime,
      operateStartTime: inspectionOperationsTicket.operationBeginTime,
      operator: inspectionOperationsTicket.operatorName,
      guardian: inspectionOperationsTicket.guarder,
      dutyLeader: inspectionOperationsTicket.dutyStackholder,
      operateEndTime: inspectionOperationsTicket.operationEndTime,
      remark: inspectionOperationsTicket.remark,
      pictureIds: inspectionOperationsTicket.pictureAttachments.map((att) => att.id).join(",")
    };
    return this.httpService.fetchWithPath(api, parameters)
      .flatMap((data) => {
        // TODO sync Error
        let inspectionOperationsTicketsDto = new InspectionOperationsTicketsDto();
        let inspectionTasksDto = new InspectionTasksDto();
        if (data.code === 200) {
          inspectionOperationsTicketsDto.syncStatus = SyncStatus.Success;
          inspectionTasksDto.status = 3;
          return this.curdService.beginTransaction()
            .updateObject(inspectionOperationsTicketsDto, {id: inspectionOperationsTicket.id}, ['syncStatus'])
            .updateObject(inspectionTasksDto, {id: inspectionOperationsTicket.taskId}, ['status'])
            .commit();
        } else {
          inspectionOperationsTicketsDto.syncStatus = this.getSyncStatus(this.inspectionSync);
          return this.curdService.beginTransaction()
            .updateObject(inspectionOperationsTicketsDto, {id: inspectionOperationsTicket.id}, ['syncStatus'])
            .commit();
        }
      })
      .map(() => true);
  }

  private postInspectionRecord(inspectionRecord: InspectionRecords): Observable<boolean> {
    let api = new API().path({ path: "exploration", method: HTTPMethods.Post });
    let parameters = {
      planId: inspectionRecord.taskId,
      planCode: inspectionRecord.author,
      recorder: inspectionRecord.noteTaker,
      explorationTime: inspectionRecord.inspectedDate,
      explorationDept: inspectionRecord.company,
      explorationLeader: inspectionRecord.stackHolder,
      explorationMan: inspectionRecord.members,
      exploreSubmitTime: +new Date(),
      saveToLocalTime: inspectionRecord.saveLocaTime,
      jobTask: inspectionRecord.taskContent,
      items1: inspectionRecord.workingArea,
      items2: inspectionRecord.powerCutScope,
      items3: inspectionRecord.powerCutDevices,
      items4: inspectionRecord.stateGrounding,
      items5: inspectionRecord.workGrounding,
      items6: inspectionRecord.keepLivePowerDevicePositions,
      items7: inspectionRecord.badges,
      items8StartTime: inspectionRecord.planedStartedTime,
      items8EndTime: inspectionRecord.planedEndTime,
      items9PowerCutTime: inspectionRecord.stopPowerStartTime,
      items9PowerCutTimeSlot: inspectionRecord.stopPowerEndTime,
      items9PowerOnTime: inspectionRecord.supplyPowerStartTime,
      items9PowerOnTimeSlot: inspectionRecord.supplyPowerEndTime,
      items10IsPowerOn: inspectionRecord.isChangingPowerLine,
      items10Remark: inspectionRecord.changingPowerLineInfo,
      items11IsElectric: inspectionRecord.isAdjacentLines,
      items11Remark: inspectionRecord.adjacentLinesRemark,
      items12: inspectionRecord.crossLineInfo,
      items13: inspectionRecord.hasDoublePowers,
      items14: inspectionRecord.devicesUnderGround,
      items15: inspectionRecord.risks,
      items16: inspectionRecord.riskLevel,
      items17: inspectionRecord.pictureAttachments.map((attachment) => attachment.id).join(","), // 附件
      items18: inspectionRecord.powerCutDiagram,
      remark: inspectionRecord.adjacentLinesRemark,
      createdTime: +new Date()
    };
    return this.httpService.fetchWithPath(api, parameters)
      .flatMap((data) => {
        let inspectionRecordsDto = new InspectionRecordsDto();
        let inspectionTasksDto = new InspectionTasksDto();
        if (data.code === 200) {
          inspectionRecordsDto.syncStatus = SyncStatus.Success;
          inspectionRecordsDto.recordsId = data["data"].id;
          inspectionTasksDto.status = 1;
          return this.curdService.beginTransaction()
            .updateObject(inspectionRecordsDto, {taskId: inspectionRecord.taskId}, ['syncStatus', 'recordsId'])
            .updateObject(inspectionTasksDto, {id: inspectionRecord.taskId}, ['status'])
            .commit();
        } else {
          inspectionRecordsDto.syncStatus = this.getSyncStatus(this.inspectionSync);
          inspectionTasksDto.status = 0;
          return this.curdService.beginTransaction()
            .updateObject(inspectionRecordsDto, {taskId: inspectionRecord.taskId}, ['syncStatus'])
            .updateObject(inspectionTasksDto, {id: inspectionRecord.taskId}, ['status'])
            .commit();
        }

      })
      .map(() => true);
  }

}

